package com.ctrip.ec.dal;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by jiang on 2018/3/22.
 */
public class EntityBase {

    private static Map<String, EntityProperty> entityProperties = new ConcurrentHashMap<>();


    private static void cacheProperty(Class<? extends EntityBase> clazz) {
        String className = clazz.getName();
        if (entityProperties.containsKey(className) == false) {
            EntityProperty property = new EntityProperty();
            DbTable dbTable = clazz.getAnnotation(DbTable.class);
            property.setTableName(dbTable.value());
            // property.pkName = null;
            // property.autoIncr = dbTable.pkAutoIncr();
            List<Field> fields = new ArrayList<>();
            fetchAllDeclaredFields(clazz, fields);

            Method[] methods = clazz.getMethods();
            for (Field field : fields) {
                if (field.isAnnotationPresent(DbColumn.class)) {
                    String columnName = field.getAnnotation(DbColumn.class).value();
                    boolean isExtend = field.getAnnotation(DbColumn.class).isExtend();

                    if (isExtend) {
                        property.getColumnsEx().add(columnName);
                    } else {
                        property.getColumns().add(columnName);
                    }

                    if (columnName.equals(dbTable.pkName())) {
                        property.setPkName(columnName);
                        property.setPkType(field.getType());
                    }

                    String getMethod = convertMethodName(columnName, true);
                    property.getColGetMethods().put(columnName, findMethod(getMethod, methods));


                    String setMethod = convertMethodName(columnName, false);
                    property.getColSetMethods().put(columnName, findMethod(setMethod, methods));

                }
            }


            entityProperties.putIfAbsent(className, property);
        }
    }

    public EntityBase() {
        //tableProperty = new TableProperty();

        cacheProperty(this.getClass());

        String className = this.getClass().getName();


        this.entityProperty = entityProperties.get(className);

    }

    public  void copyFrom (EntityBase entity){
        for(String col : entity.property().getColumns()){
            this.fieldValue(col,entity.fieldValue(col));
        }
    }






    /**
     * 查找本类及父类的字段
     */
    private static void fetchAllDeclaredFields(Class clazz, List<Field> fields) {
        if (EntityBase.class.isAssignableFrom(clazz) && clazz != EntityBase.class) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            fetchAllDeclaredFields(clazz.getSuperclass(), fields);
        }

    }

    private static Method findMethod(String methodName, Method[] methods) {
        for (Method m : methods) {
            if (m.getName().equals(methodName)) {
                return m;
            }
        }
        return null;
    }

    private EntityProperty entityProperty;

    public EntityProperty property() {
        return entityProperty;
    }

    public static String getTableName(Class<? extends EntityBase> clazz) {

        cacheProperty(clazz);

        return entityProperties.get(clazz.getName()).getTableName();
    }


    public boolean add() {
        Object pkValue = this.fieldValue(this.property().getPkName());
        if (pkValue == null || pkValue.equals(0) || pkValue.equals(0L)) {
            return true;
        } else {
            return false;
        }
    }

    public static String convertMethodName(String columnName, boolean isGet) {
        StringBuilder methodName = new StringBuilder();

        if (isGet) {
            methodName.append("get");
        } else {
            methodName.append("set");
        }
        boolean needUpperCase = true;
        for (char ch : columnName.toCharArray()) {
            if (ch == '_') {
                needUpperCase = true;
            } else {
                if (needUpperCase) {
                    if (Character.isLowerCase(ch)) {
                        ch -= 32;
                    }
                    needUpperCase = false;
                }
                methodName.append(ch);
            }
        }
        return methodName.toString();
    }

    public void fieldValue(String columnName, Object value) {
        Method method = this.entityProperty.getColSetMethods().get(columnName);
        if (method == null) {
            return;
            //throw new RuntimeException(this.getClass().getName() + "没有找到" + columnName + "字段对应的set方法");
        }
        try {
            method.invoke(this, value);
        } catch (Exception ex) {
            throw new RuntimeException(ex.getMessage());
        }
    }

    public Object fieldValue(String columnName) {
        Method method = this.entityProperty.getColGetMethods().get(columnName);
        if (method == null) {
            //throw new RuntimeException(this.getClass().getName() + "没有找到" + columnName + "字段对应的get方法");
            return null;
        }
        try {
            if (method != null) {
                return method.invoke(this);
            } else {
                return null;
            }
        } catch (Exception ex) {
            throw new RuntimeException(ex.getMessage());
        }
    }


}